package core;

import infrastructure.exceptions.PrivilidgesException;
import infrastructure.exceptions.operations.OperationException;
import inftrastructure.exceptions.ClientRuntimeException;

import java.io.IOException;
import java.io.Serializable;
import java.util.Iterator;

import remote.RemoteInvocation;
import server.IServerSession;
import server.querry.Condition;
import dal.IPet;
import dal.Pet;
import dal.Pet_type;
import dal.User;

public class ServerSession implements IServerSession,Serializable{

	private static final long serialVersionUID = 2411869876319862514L;
	
	/** Keeps serssion id to the server*/
	private long sessionId;
	
	/** Keeps session connection*/
	protected transient ServerFacade serverAccess;
	
	/** Keeps user of the session*/
	private User sessionUser;
	
	

	protected ServerSession(long sessionId){
		this.sessionId = sessionId;
		sessionUser = null;
	}
	
	public void setServerAccess(ServerFacade connection){
		serverAccess = connection;
	}
	
	public User getSessionUser() {
		return sessionUser;
	}
	
	@Override
	public Iterator<Pet_type> getAllPetTypes() throws PrivilidgesException {
		
		RemoteInvocation invoker;
		
		try {
			invoker = new RemoteInvocation(this.getClass(),
					this.getClass().getMethod("getAllPetTypes", new Class<?>[]{}),
						sessionId, new Serializable[]{});
		} catch(Exception ex){
			throw new ClientRuntimeException("Bug !!!",ex);
		}	
		
		return serverAccess.remoteConnection.invoke(invoker);
	}

	@Override
	public Iterator<IPet> getAllPets() throws PrivilidgesException {
		RemoteInvocation invoker;
		
		try {
			invoker = new RemoteInvocation(this.getClass(),
					this.getClass().getMethod("getAllPets", new Class<?>[]{}),
						sessionId, new Serializable[]{});
		} catch(Exception ex){
			throw new ClientRuntimeException("Bug !!!",ex);
		}	
		
		Iterator<IPet> petsIterator = serverAccess.remoteConnection.invoke(invoker);
		return new PetsSerializableIteratorWrapper(petsIterator, this);
	}

	@Override
	public Iterator<IPet> getPets(Condition querry) throws PrivilidgesException {
		RemoteInvocation invoker;
		
		try {
			invoker = new RemoteInvocation(this.getClass(),
					this.getClass().getMethod("getPets", new Class<?>[]{Condition.class}),
						sessionId, new Serializable[]{querry});
		} catch(Exception ex){
			throw new ClientRuntimeException("Bug !!!",ex);
		}	
		
		Iterator<IPet> petsIterator = serverAccess.remoteConnection.invoke(invoker);
		return new PetsSerializableIteratorWrapper(petsIterator, this);
	}

	@Override
	public void giveForAdoption(IPet petToDeliver) throws OperationException,
			PrivilidgesException {
		
		RemoteInvocation invoker;
		
		try {
			invoker = new RemoteInvocation(this.getClass(),
					this.getClass().getMethod("giveForAdoption", new Class<?>[]{IPet.class}),
						sessionId, new Serializable[]{petToDeliver});
		} catch(Exception ex){
			throw new ClientRuntimeException("Bug !!!",ex);
		}	
		
		serverAccess.remoteConnection.invoke(invoker);
		
	}

	@Override
	public void removePetFromSystem(Integer  id) throws OperationException,
			PrivilidgesException {
		RemoteInvocation invoker;
		
		try {
			invoker = new RemoteInvocation(this.getClass(),
					this.getClass().getMethod("removePetFromSystem", new Class<?>[]{Integer.class}),
						sessionId, new Serializable[]{id});
		} catch(Exception ex){
			throw new ClientRuntimeException("Bug !!!",ex);
		}	
		
		serverAccess.remoteConnection.invoke(invoker);
		
	}
	
	private void writeObject(java.io.ObjectOutputStream out) throws IOException{
		throw new IOException("This method should not be called ..");
	}
	
	private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
		sessionId = in.readLong();	
		sessionUser = (User)in.readObject();
	}

	@Override
	public long getSessionId() {
		return sessionId;
	}

	public byte[] getPetPicture(Integer petId){
		RemoteInvocation invoker;
		
		try {
			invoker = new RemoteInvocation(this.getClass(),
					this.getClass().getMethod("getPetPicture", new Class<?>[]{Integer.class}),
						sessionId, new Serializable[]{petId});
		} catch(Exception ex){
			throw new ClientRuntimeException("Bug !!!",ex);
		}	
		
		return serverAccess.remoteConnection.invoke(invoker);
	}
	

}
